﻿using ScFramework.Core;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 仅主机
/// </summary>
public partial class ConnectManager : EntityDataMgr<SRigidUnionVEx,SColliderVEx>,IBelongUser
{
    /// <summary>
    /// 连接对
    /// </summary>
    public class ConnectPair
    {
        /// <summary>
        /// 组件id,左16为实体id,右16为组件编号
        /// </summary>
        public UInt32 Comp1;
        public UInt32 Comp2;


        public ConnectPair(uint c1,uint c2)
        {
            Comp1 = c1;
            Comp2 = c2;
        }
        /*public override int GetHashCode()
        {
            return (int)MathExtensions.UnorderedPairHash(Comp1, Comp2);
        }*/
        public override bool Equals(object obj)
        {
            if(obj is ConnectPair p)
            {
                return (Comp1 == p.Comp1 && Comp2 == p.Comp2) || (Comp1 == p.Comp2 && Comp2 == p.Comp1);
            }
            else
            {
                return false;
            }
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
 //   Dictionary<UInt32, List<SColliderVEx>> rigidsBoxsDic;
    /// <summary>
    /// 存在的连接对集合
    /// </summary>
    List<ConnectPair> connectPairs;
    /// <summary>
    /// rigidunion预设的id
    /// </summary>
    UInt16 rigidUnionID;


    Dictionary<ushort, int> belongDic = null;

    public override void OnInit(object args)
    {
        base.OnInit(args);
        rigidUnionID = EntityUtilities.GetIdByName("RigidUnion");
        connectPairs = new List<ConnectPair>();
        belongDic = new Dictionary<ushort, int>();
  //      rigidsBoxsDic = new Dictionary<uint, List<SColliderVEx>>();
    }
    public override void OnDestroy()
    {
        base.OnDestroy();
        belongDic.Clear();
    }

    public bool ContainConnect(ConnectPair pair)
    {
        if (connectPairs.Count > 0)
        {
            Debug.Log(connectPairs[0].GetHashCode() + " " + pair.GetHashCode());
        }
        return connectPairs.Find(s => s.Equals(pair)) != null;
    }
  
    public override void OnValueChanged2(SColliderVEx com, ushort vid, object v)
    {
        base.OnValueChanged2(com, vid, v);
        
    }
    [RegisterEvent(PhysicsProcessEvent.StartCombine)]
    void StartCombine(Tuple<List<Entity>, Vector3> args)
    {
        foreach(var x in args.Item1)
        {
            DoDelete(x.Data.EntityIdentity.right());
            var colliders = x.GetComponents<SCollider>();
            foreach(var c in colliders)
            {
                c.SData.SetValue<UInt32>("AttachedRigidUnion", 0);
            }
            Debug.Assert(x.GetComponents<SComBody>().Count == 1);
            var body = x.GetComponent<SComBody>();
            Debug.Assert(body.PresentPos == 0);
            body.SData.SetValue<int>("PresentPos", 1);
        }
    }
    void DoDelete(ushort eid)
    {
        

        while (connectPairs.Find(s => s.Comp1.left() == eid || s.Comp2.left() == eid) != null)
        {
            var pairs = connectPairs.Find(s => s.Comp1.left() == eid || s.Comp2.left() == eid);

            BreakTwoCollider(pairs.Comp1, pairs.Comp2);

        }
        var cs = _es2.FindAll(s => s.CompIdentity.left() == eid);
        List<uint> rs = new List<uint>();
        foreach (var x in cs)
        {
            rs.UniqueAdd(x.AttachedRigidUnion);
        }

        foreach (var x in rs)
        {
            Dispatch(EntityDataEvent.Delete, x.left());

        }
        foreach(var r in _es1)
        {
            ResetRigidCenter(r.CompIdentity);
        }
        RefreshBelongUsr();
    }
    public override void OnDeleted2(ushort eid)
    {

        DoDelete(eid);


        base.OnDeleted2(eid);
    }
    public void AddRigidForCollider(UInt32 compID)
    {
 //       Debug.Log("com=" + compID);
        var co = Get2(compID);
        var body = new SComBodyVEx(EntityDataBase.GetEntityData(compID.left()).GetComponentData<SComBody>());
        Debug.Assert(co.AttachedRigidUnion == 0);
        var rpos = co.LocalPosition;
        co.LocalPosition = Vector3.zero;
        co.LocalRotation = body.MeshRotate * 90f;
        co.LocalIsFliped=body.IsFliped; 
        if (co.AttachedRigidUnion == 0)
        {

            Dispatch(EntityDataEvent.Create, new DataCreateArgs
            {
                ID = rigidUnionID,
                actions = (EntityData d) =>
                  {
                      co.AttachedRigidUnion = d.GetComponentData<SRigidUnion>().CompIdentity;
                      d.GetComponentData<SRigidUnion>().SetValue<Vector3>("LocalPosition",
                        rpos);
                  }
             });
        }
    }
    void RefreshBelongUsr()
    {
        belongDic.Clear();
        var cores = _es2.FindAll(s => EntityDataBase.GetEntityData(s.CompIdentity.left()).GetComponentData<SCore>() != null).ConvertAll(s =>new SComBodyVEx(EntityDataBase.GetEntityData(s.CompIdentity.left()).GetComponentData<SComBody>())) ;
        List<ushort> que = new List<ushort>();
        cores.RemoveAll(s => s.PresentPos != 0);
        HashSet<ushort> use = new HashSet<ushort>();
        foreach (var c in cores)
        {
            Debug.Assert(c.UserID > 0);
            Debug.Assert(belongDic.ContainsValue(c.UserID) == false);
            belongDic[c.CompIdentity.left()] = c.UserID;
            que.Add(c.CompIdentity.left());
            use.Add(c.CompIdentity.left());
        }
        for(int i = 0; i < que.Count; i++)
        {
            ushort eid = que[i];
            foreach(var x in Gets2(eid))
            {
                belongDic[x.AttachedRigidUnion.left()] = belongDic[eid];
            }
            var connect = connectPairs.FindAll(s => s.Comp1.left() == eid || s.Comp2.left() == eid).ConvertAll(s => s.Comp1.left() == eid ? s.Comp2.left() : s.Comp1.left());
            foreach(var x in connect)
            {
                Debug.Assert(x != eid);
                if (use.Contains(x))
                {
                    Debug.Assert(belongDic[x] == belongDic[eid]);
                }
                else
                {
                    belongDic[x] = belongDic[eid];
                    use.Add(x);
                    que.Add(x);
                }
            }
        }
    }
    /// <summary>
    /// 当一组物体到达世界中时,为其产生连接信息
    /// </summary>
    /// <param name="args"></param>
    [RegisterEvent(ObjectPresentPosEvent.ToWorld)]

    void WhenToWorld(ObjectPresentPosChangeArgs args)
    {
        if (args.LastPresentPos != ObjectPresentPos.Bench)
        {
            return;
        }
        Dictionary<Tuple<Vector3Int, Vector3Int>, InterfaceInfo> dic = new Dictionary<Tuple<Vector3Int, Vector3Int>, InterfaceInfo>();
        foreach (var body in args.Entities)
        {
            foreach (var xxx in body.Data.GetEntity().GetComponentDatas<SCollider>())
            {
                Debug.Log(xxx);
                var xx = new SColliderVEx(xxx);
                AddRigidForCollider(xx.CompIdentity);
                //    Debug.Log("r="+xx.AttachedRigidUnion);
                Debug.Assert(xx.ConnectState.Count == xx.LocalMeshPos.Count);
                for (int o = 0; o < xx.ConnectState.Count; o++)
                {

                    int state = xx.ConnectState[o];

                    bool isf = body.IsFliped;
                    int mro = body.MeshRotate;
                    Vector3Int lp = xx.LocalMeshPos[o];
                    //      Debug.Assert(body.SubBoxsLocalPos.Contains(lp));
                    Vector3Int pos = SComBodyEx.WorldMeshPos(body.MeshPos, isf, mro, lp);
                    UInt32 id = xx.CompIdentity;
                    for (int i = 0; i < 4; i++)
                    {
                        if ((state & (1 << i)) > 0)
                        {
                            Vector3Int npos = SComBodyEx.WorldMeshPos(body.MeshPos, isf, mro, SComBodyEx.LocalDirPos(lp, i));
                            Debug.Assert(false == dic.ContainsKey(new Tuple<Vector3Int, Vector3Int>(pos, npos)));
                            var info = new InterfaceInfo
                            {
                                CompId = id,
                                LocalMeshPos = xx.LocalMeshPos[o],
                                InterfacePos = i
                            };
                            dic[new Tuple<Vector3Int, Vector3Int>(pos, npos)] = info;
                            if (dic.ContainsKey(new Tuple<Vector3Int, Vector3Int>(npos, pos)))
                            {
                                Connect(info, dic[new Tuple<Vector3Int, Vector3Int>(npos, pos)]);
                            }
                        }
                    }
                }


            }
        }
        foreach(var r in _es1)
        {
            ResetRigidCenter(r.CompIdentity);
        }
        RefreshBelongUsr();

    }

    public int GetBelongUser(ushort eid)
    {
        if (belongDic.ContainsKey(eid))
        {
            return belongDic[eid];
        }
        else return 0;
    }

    public List<ushort> GetAllEntitiesByUserID(int usr)
    {
        var ans = new List<ushort>();
        foreach(var x in belongDic)
        {
            if (x.Value == usr) ans.Add(x.Key);
        }
        return ans;
    }

    public struct InterfaceInfo
    {
        public UInt32 CompId;
        public Vector3Int LocalMeshPos;
        /// <summary>
        /// 0,1,2,3分别代表右上左下
        /// </summary>
        public int InterfacePos;
    }
}
public interface IBelongUser : IModuleInnerInterface
{
    int GetBelongUser(ushort eid);
    List<ushort> GetAllEntitiesByUserID(int usr);
}